package myJs.tool

import myJs.Utils._

import scala.scalajs.js.Dynamic.{global => g}
import myJs.myPkg.DatepickerOptions
import myJs.myPkg.jquery.{$, _}
import myJs.tool.Pojo.FilterContentData
import org.scalajs.dom.{Element, Event, document}
import scalatags.Text.{TypedTag, all}
import scalatags.Text.all._

import scala.scalajs.js.Date
import scala.scalajs.js.annotation.JSExport
import myJs.Implicits._
import myJs.tool.Tool._

import scala.concurrent.Future
import org.scalajs.dom.{Event, _}

import scala.scalajs.js
import scala.scalajs.js.JSConverters._

/**
 * Created by yz on 28/5/2020
 */
trait TableFilterTool {

  def clickHide = {
    $(document).on("click", (y: Element, e: Event) => {
      val trueY = e.target.asInstanceOf[Element]
      val b = $(trueY).hasClass("select2-selection__choice__remove") ||
        $(trueY).hasClass("select2-search__field") ||
        $(trueY).hasClass("filterContent") ||
        $(trueY).parents().hasClass("filterContent")
      if (!b) {
        $(".filterContent").hide()
      }
    })
  }

  def filterContentValueRevert(jq: JQuery) = {
    $(jq).find(":input.filterInput").foreach { inY =>
      val beforeValue = $(inY).dataBeforeValue
      if ($(inY).hasClass("select2MultiInput")) {
        $(inY).select2Val(beforeValue.split(";").toJSArray)
      } else if ($(inY).hasClass("myDatepicker")) {
        $(inY).datepicker("update", beforeValue)
      } else {
        $(inY).`val`(beforeValue)
      }
    }
  }

  def filterContentFillBeforeValue(jq: JQuery) = {
    jq.find(":input.filterInput").mapElems(y => y).foreach { inY =>
      val v = Tool.getValues(inY)
      val vStr = v.mkString(";")
      $(inY).attr("data-beforeValue", vStr)
    }
  }

  def getFilterDataFieldName(jq: JQuery) = {
    jq.attr("filter-data-field").get
  }

  def getFilterDataFieldName(y: Element) = {
    $(y).attr("filter-data-field").get
  }

  def timeBefore = (dateStr: String, dbDateStr: String) => {
    val date = new Date(dateStr)
    val dbDate = new Date(dbDateStr)
    dbDate.setUTCHours(0, 0, 0, 0)
    date.getTime() <= dbDate.getTime()
  }

  def timeAfter = (dateStr: String, dbDateStr: String) => {
    val date = new Date(dateStr)
    val dbDate = new Date(dbDateStr)
    dbDate.setUTCHours(0, 0, 0, 0)
    date.getTime() >= dbDate.getTime()
  }

  def getAscLi = {
    li(`class` := "myLi hasHover mySortLi",
      span(`class` := "sortFa",
        i(`class` := "fa fa-sort-alpha-asc")
      ),
      span(messages("ascendingSort"))
    )
  }

  def getDescLi = {
    li(`class` := "myLi hasHover mySortLi",
      span(`class` := "sortFa",
        i(`class` := "fa fa-sort-alpha-desc")
      ),
      span(messages("descendingSort"))
    )
  }

  def getFooter = {
    div(`class` := "modal-footer bg-info",
      button(`type` := "button", `class` := "btn btn-sm blue myConfirm",
        messages("confirm")),
      button(`type` := "button", `class` := "btn btn-default myHide",
        messages("close"))
    )
  }

  def initFilterContent(textSortDatas: List[FilterContentData] = List[FilterContentData](),
                        sortDatas: List[FilterContentData] = List[FilterContentData](),
                        timeSortDatas: List[FilterContentData] = List[FilterContentData](),
                        select2SortDatas: List[FilterContentData] = List[FilterContentData](), parentId: String = "",
                        showShowYear: Boolean = false
                       ) = {
    val textSortContentHtml = textSortDatas.map { x =>
      div(id := s"${x.fieldName}Content", `class` := "menuContent filterContent", display := "none",
        filterDataField := s"${x.fieldName}", attr("label") := x.label,
        form(`class` := "form-horizontal myForm",
          ul(`class` := "myUl",
            getAscLi,
            getDescLi,
            li(`class` := "myDivider"),
            li(`class` := "myLi",
              div(marginBottom := 10,
                span(`class` := "fa fa-filter"),
                s" ${messages("screening")}"
              ),
              div(`class` := "form-group",
                div(`class` := "col-sm-12",
                  input(`type` := "text", `class` := "form-control filterInput valueInput textInput",
                    name := x.fieldName, width := "100%")
                )
              )
            ),
          )
        ),
        getFooter
      )
    }.mkString("&nbsp;")

    val selectSortContentHtml = sortDatas.map { x =>
      div(id := s"${x.fieldName}Content", `class` := "menuContent filterContent",
        display := "none",
        filterDataField := s"${x.fieldName}", attr("label") := x.label,
        form(`class` := "form-horizontal myForm",
          ul(`class` := "myUl",
            getAscLi,
            getDescLi,
            li(`class` := "myDivider"),
            li(`class` := "myLi",
              div(marginBottom := 10,
                span(`class` := "fa fa-filter"),
                s" ${messages("screening")}"
              ),
              div(`class` := "form-group", marginBottom := 10,
                div(`class` := "col-sm-12",
                  select(`type` := "text", `class` := "form-control filterInput valueInput selectInput",
                    name := x.fieldName, width := "100%",
                    x.values.map { v =>
                      option(value := v, v)
                    }
                  )
                )
              ),
            ),
          )
        ),
        getFooter
      )
    }.mkString("&nbsp;")

    val select2SortContentHtml = select2SortDatas.map { x =>
      div(id := s"${x.fieldName}Content", `class` := "menuContent filterContent",
        display := "none",
        filterDataField := s"${x.fieldName}", attr("label") := x.label,
        form(`class` := "form-horizontal myForm",
          ul(`class` := "myUl",
            getAscLi,
            getDescLi,
            li(`class` := "myDivider"),
            li(`class` := "myLi",
              div(marginBottom := 10,
                span(`class` := "fa fa-filter"),
                s" ${messages("screening")}"
              ),
              div(`class` := "form-group",
                div(`class` := "col-sm-12",
                  select(`type` := "text", `class` := "form-control filterInput select2MultiInput",
                    name := x.fieldName, width := "100%")
                )
              )
            ),
          )
        ),
        getFooter
      )
    }.mkString("&nbsp;")

    val timeSortContentHtml = timeSortDatas.map { x =>
      div(id := s"${x.fieldName}Content", `class` := "menuContent filterContent",
        display := "none",
        filterDataField := s"${x.fieldName}", attr("label") := x.label,
        form(`class` := "form-horizontal myForm",
          ul(`class` := "myUl",
            getAscLi,
            getDescLi,
            if(showShowYear){
              li(`class` := "myLi hasHover myYear",
                span(`class` := "",
                  i(`class` := "fa fa-calendar"),
                  " "
                ),
                span(`class` := "text", s"${messages("showYear")}")
              )
            }else{
              span()
            },
            li(`class` := "myDivider"),
            li(`class` := "myLi",
              div(marginBottom := 10,
                span(`class` := "fa fa-filter"),
                s" ${messages("dateRange")}"
              ),
              div(`class` := "form-group", marginBottom := 10,
                div(`class` := "col-sm-12",
                  input(`type` := "text", `class` := "filterInput myDatepicker form-control startTime",
                    name := "startTime", width := "100%", placeholder := s"${messages("from")}", readonly)
                )
              ),
              div(`class` := "form-group",
                div(`class` := "col-sm-12",
                  input(`type` := "text", `class` := "filterInput myDatepicker form-control endTime",
                    name := "endTime", width := "100%", placeholder := s"${messages("end")}", readonly)
                )
              ),
            ),

          )
        ),
        getFooter
      )
    }.mkString("&nbsp;")

    val contentHtml = List(textSortContentHtml, selectSortContentHtml, select2SortContentHtml, timeSortContentHtml).
      mkString("&nbsp;")
    val finalParentId = if (parentId.isEmpty) "body" else s"#${parentId}"
    $(s"${finalParentId} #allFilterContent").html(contentHtml)
  }

  def fillSortHtml(y: Element, parentId: String = "") = {
    val parentElem = if (parentId.isEmpty) "" else s"#${parentId}"
    val iJq = $(y).find("i")
    val isAsc = !iJq.hasClass("fa-sort-alpha-desc")
    val sortTypeStr = if (isAsc) {
      "asc"
    } else "desc"
    val orderHtml = if (isAsc) {
      span(color := "red", messages("ascending"))
    } else span(color := "blue", messages("descending"))
    val filterContentJq = $(y).parents(".filterContent")
    val label = filterContentJq.attr("label").toString
    val fieldName = Tool.getFilterDataFieldName(filterContentJq)
    val conditionHtml = span(`class` := "eachFCParent",
      filterDataField := fieldName, sortType := sortTypeStr,
      span(`class` := "eachFilterCondition",
        span(s"${label} , "),
        orderHtml,
      ),
      sup(`class` := "mySup sortSub myRemoveSort",
        i(`class` := "fa fa-times-circle")
      )
    ).render
    $(s"${parentElem} #sortCondition").html(conditionHtml)
    $(s"${parentElem} #sortCondition").parent().show()
  }

  def hideFilterContent(y: Element) = {
    $(y).parents(".filterContent").hide()
  }

  def hideFilterContentWithRevert(y: Element) = {
    Tool.filterContentValueRevert($(y).parents(".filterContent"))
    Tool.hideFilterContent(y)
  }

  def getQueryMap(parentId: String) = {
    val parentElem = if (parentId.isEmpty) "body" else s"#${parentId}"
    val filterMap = $(s"${parentElem} .filterContent").mapElems(y => y).flatMap { y =>
      val fieldName = Tool.getFilterDataFieldName(y)
      $(y).find(":input.filterInput").mapElems(y => y).map { inY =>
        val name = $(inY).attr("name").toString
        val v = Tool.getValues(inY)
        val finalName = s"${fieldName}.${name}"
        (finalName, v)
      }
    }.toMap
    val eachParent = $(s"${parentElem} sup.sortSub").parents(".eachFCParent")
    val sortMap = if (eachParent.mapElems(y => y).isEmpty) {
      Map[String, js.Array[String]]()
    } else {
      val order = eachParent.attr("sort-type").toString
      val sort = Tool.getFilterDataFieldName(eachParent)
      Map("sort" -> js.Array(sort), "order" -> js.Array(order))
    }
    filterMap ++ sortMap
  }

  def sortActive(y: Element, parentId: String) = {
    val parentElem = if (parentId.isEmpty) "body" else s"#${parentId}"
    val iJq = $(y).find("i")
    val isAsc = !iJq.hasClass("fa-sort-alpha-desc")
    val order = if (!isAsc) {
      "desc"
    } else "asc"
    val fieldName = Tool.getFilterDataFieldName($(y).parents(".filterContent"))
    val faClass = if (isAsc) "fa-long-arrow-up" else "fa-long-arrow-down"
    $(s"${parentElem} button").find(".afterSortFa").removeClass("fa-long-arrow-up").
      removeClass("fa-long-arrow-down")
    $(s"${parentElem} button[filter-data-field=${fieldName}]").find(".afterSortFa").addClass(faClass)
    $(s"${parentElem} .myLi").removeClass("active")
    $(y).addClass("active")
  }

  def removeSortActive(y: Element, parentId: String) = {
    val parentElem = Tool.getParentElem(parentId)
    val fieldName = Tool.getFilterDataFieldName($(y).parents(".eachFCParent"))
    $(s"${parentElem} #sortCondition").html("")
    $(s"${parentElem} #sortCondition").parent().hide()
    $(s"${parentElem} button[filter-data-field=${fieldName}]").find(".afterSortFa").
      removeClass("fa-long-arrow-up").removeClass("fa-long-arrow-down")
    $(s"${parentElem} .myLi").removeClass("active")
  }

  def fillConditionHtml(parentId: String, map: Map[String, Map[String, String]] = Map[String, Map[String, String]]()) = {
    val parentElem = Tool.getParentElem(parentId)
    val parentJq = $(parentElem)
    val textTs = $(s"${parentElem} .textInput").mapElems { y =>
      val fieldName = $(y).attr("name").toString
      val columnName = $(y).parents(".filterContent").attr("label").toString
      (fieldName, columnName)
    }
    val textConditionHtml = textTs.map { case (fieldName, columnName) =>
      val curV = $(s"${parentElem}").findInputByName(fieldName).myVal
      if (curV.isEmpty) {
        ""
      } else {
        span(`class` := "eachFCParent",
          span(`class` := "eachFilterCondition",
            span(s"${columnName} "),
            span(color := "red", "LIKE"),
            s" ${curV}",
          ),
          sup(`class` := "mySup myRemove", filterDataField := fieldName,
            i(`class` := "fa fa-times-circle")
          )
        ).render

      }
    }.mkString(" ")

    val selectTs = $(s"${parentElem} .selectInput").mapElems { y =>
      val fieldName = $(y).attr("name").toString
      val columnName = $(y).parents(".filterContent").attr("label").toString
      (fieldName, columnName)
    }
    val selectConditionHtml = selectTs.map { case (fieldName, columnName) =>
      val curV = $(s"${parentElem}").findInputByName(fieldName).myVal
      if (curV.isEmpty) {
        ""
      } else {
        span(`class` := "eachFCParent",
          span(`class` := "eachFilterCondition",
            span(s"${columnName} "),
            span(color := "red", messages("equals")),
            s" ${curV}",
          ),
          sup(`class` := "mySup myRemove", filterDataField := fieldName,
            i(`class` := "fa fa-times-circle")
          )
        ).render
      }
    }.mkString(" ")

    val timeConditionHtml = $(s"${parentElem} .filterContent").mapElems(y => y).map { y =>
      val fieldName = Tool.getFilterDataFieldName(y)
      val columnName = $(y).attr("label").toString
      val startTime = $(y).find(":input[name='startTime']").myVal
      val endTime = $(y).find(":input[name='endTime']").myVal
      val trueStartTime = if (startTime.isEmpty) messages("none") else startTime
      val trueEndTime = if (endTime.isEmpty) messages("none") else endTime
      val inConditionHtml = if (startTime.isEmpty && endTime.isEmpty) {
        ""
      } else {
        span(`class` := "eachFCParent",
          span(`class` := "eachFilterCondition",
            span(s"${columnName}"),
            s" ${trueStartTime} - ${trueEndTime}",
          ),
          sup(`class` := "mySup myRemove", filterDataField := s"${fieldName}",
            i(`class` := "fa fa-times-circle")
          )
        ).render
      }
      inConditionHtml
    }.mkString(" ")

    val select2MultiTs = parentJq.find(".select2MultiInput").mapElems { y =>
      val fieldName = $(y).attr("name").toString
      val columnName = $(y).parents(".filterContent").attr("label").toString
      (fieldName, columnName)
    }
    val select2MultiConditionHtml = select2MultiTs.map { case (fieldName, columnName) =>
      val curV = parentJq.findInputByName(fieldName).select2Val
      val trueV = map.get(fieldName).map { inMap =>
        curV.map(x => inMap(x))
      }.getOrElse(curV)
      if (trueV.isEmpty) {
        ""
      } else {
        span(`class` := "eachFCParent",
          span(`class` := "eachFilterCondition",
            span(s"${columnName} "),
            span(color := "red", "IN"),
            s" ${trueV}",
          ),
          sup(`class` := "mySup myRemove", filterDataField := fieldName,
            i(`class` := "fa fa-times-circle")
          )
        ).render
      }
    }.mkString(" ")

    val conditionHtml = List(textConditionHtml, selectConditionHtml, timeConditionHtml, select2MultiConditionHtml).mkString(" ")
    if (conditionHtml.trim.isEmpty) {
      $(s"${parentElem} #filterCondition").html("")
      $(s"${parentElem} #filterCondition").parent().hide()
    } else {
      $(s"${parentElem} #filterCondition").html(conditionHtml)
      $(s"${parentElem} #filterCondition").parent().show()
    }
  }

  def clearInput(y: Element, parentId: String) = {
    val parentElem = Tool.getParentElem(parentId)
    val fieldName = Tool.getFilterDataFieldName(y)
    Tool.getInputByName(fieldName, parentId).not(":checkbox").`val`("")
    $(s"${parentElem} #${fieldName}Content").findInputByName("startTime").datepicker("update", "")
    $(s"${parentElem} #${fieldName}Content").findInputByName("endTime").datepicker("update", "")
    if (Tool.getInputByName(fieldName).hasClass("select2MultiInput")) {
      Tool.getInputByName(fieldName).select2Val(js.Array[String]())
    }
  }

  def removeCondition(y: Element, parentId: String, refreshTableF: () => Future[Any]) = {
    Tool.clearInput(y, parentId)
    Tool.fillConditionHtml(parentId = parentId)
    refreshTableF()
  }

  def execSort(y: Element, parentId: String, refreshTableF: () => Future[Any]) = {
    Tool.fillSortHtml(y, parentId)
    Tool.sortActive(y, parentId)
    Tool.hideFilterContentWithRevert(y)
    refreshTableF()
  }

  def confirmFilter(y: Element, parentId: String, refreshTableF: () => Future[Any],
                    map: Map[String, Map[String, String]] = Map[String, Map[String, String]]()) = {
    Tool.hideFilterContent(y)
    Tool.fillConditionHtml(parentId = parentId, map)
    refreshTableF()
  }

  def removeSort(y: Element, parentId: String, refreshTableF: () => Future[Any]) = {
    Tool.removeSortActive(y, parentId)
    refreshTableF()
  }

  def filterContentShowInModal(y: Element, parentId: String) = {
    $(".filterContent").hide()
    val fieldName = Tool.getFilterDataFieldName(y)
    val parentElem = Tool.getParentElem(parentId)
    val contentId = s"${parentElem} #${fieldName}Content"
    val yTop = $(y).offset().top - $(s"${parentElem} .modal-dialog").css("margin-top").px2Int -
      $(s"${parentElem} .modal-header").css("height").px2Int + $(y).height() + 2
    val pageWidth = document.body.clientWidth
    val yTotalLeft = $(y).offset().left
    val yLeft = yTotalLeft - $(s"${parentElem} .modal-dialog").css("margin-left").px2Double
    val width = 210
    val trueYLeft = if (yTotalLeft + width > pageWidth) pageWidth - 220 - 6 else yLeft - 3
    $(s"${contentId}").css("top", yTop.toInt).css("left", trueYLeft.toInt).width(width)
    $(s"${contentId}").show()
  }


}
